<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel='stylesheet' href='../rurple.css' type='text/css'>
<title>31. 全局是坏事</title>
</head>
<body>

<h2 class="title">31. <span class="pykeyword">全球化</span>是坏事.</h2>
<p>假设你正在和朋友写一个长的程序d.  因为你学习过良好的编程习惯, 所以你的变量名会使用描述性名称.  但是你会想: <i>那么我的朋友会不会使用了相同的变量名呢?  如果我改了我的变量的值, 那会不会不小心把它的变量的值给改了呢?</i></p>  
<p>Python 有一种方法来避免这样的问题： <i>命名空间</i>.  这可以避免程序片断中的变量互相影响.  我们在这节课中学习一下命名空间.</p>

<!--==============================-->
<hr width="50%">
<h3 class="section">局部变量.</h3>
<p>这里有一个简单的例子:</p>
<pre>
&gt;&gt;&gt; a = 1
&gt;&gt;&gt; <span class="keyword">def</span> my_function():
...     a = 3
...     <span class="keyword">print</span> a
...    

&gt;&gt;&gt; my_function()
3

&gt;&gt;&gt; <span class="keyword">print</span> a
1
</pre>
<p>你是否感到惊奇，变量 <tt>a</tt> 的值没有改变?  我们看看发生了什么.</p>
<p>最初， 你定义了变量 "<tt>a</tt>" 并把它的值设置成 1.  然后在一个函数中, 你 "显然地" 把变量 "<tt>a</tt>" 的值设置成了 3.  事实上, 你所作的是在函数中创建了一个 <u>新变量</u>  "<tt>a</tt>" , 然后把它的值设置成了 3.  函数之外的其他变量 "<tt>a</tt>" 并没有被改变.</p>
<p>Python 在每个函数的内部自动创建了一个 <i>命名空间</i> , 使得变量名是一个唯一值, 这样他与函数之外的同名变量就独立开来.  命名空间就像一个小的记事本,使 Python 可以跟踪所有的变量名.  你可以想象成 Python 为每个函数创建了唯一的记事本, 这样你就不用担心有变量名重复的问题了.</p>
<p>在一个函数内部定义的变量，在函数执行完之后就会失效; 我们说他们 <i>越界</i>.</p>
<pre>
&gt;&gt;&gt; <span class="keyword">def</span> simple_function():
...     local_variable = <span class="string">"I'm here!"</span>
...     <span class="keyword">print</span> local_variable
...    
&gt;&gt;&gt; simple_function()
I'm here!

&gt;&gt;&gt; <span class="keyword">print</span> local_variable
Traceback (most recent call last):
  File "&lt;input&gt;", line 1, in ?
NameError: name <span class="string">'local_variable'</span> is not defined
</pre>
<p>上面显示了命名空间的使用错误, 但是我们究竟应该如何修改一个函数内部的变量呢?  比如, 我们想记录一下一个函数被调用了多少次. 我们当然做得到, 我们可以使用 Python 的关键字 <span class="pykeyword">global</span>.</p>
<pre>
&gt;&gt;&gt; number_of_times = 0
&gt;&gt;&gt; <span class="keyword">def</span> two_year_old_child():
...     <span class="keyword">global</span> number_of_times
...     number_of_times += 1
...     <span class="keyword">print</span> <span class="string">"Why?          %s times"</span> % number_of_times
...    
&gt;&gt;&gt; two_year_old_child()
Why?          1 times

&gt;&gt;&gt; two_year_old_child()
Why?          2 times

&gt;&gt;&gt; two_year_old_child()
Why?          3 times

&gt;&gt;&gt; <span class="keyword">print</span> number_of_times
3
</pre>
<p><small>[当然，我们应该显示 "1 time", 不应该有那个l 's'.]</small></p>
<p>通过使用关键字 <span class="pykeyword">global</span>, 我们告诉 Python <u>不要</u> 不要在函数中创建局部变量, 而使用函数"外面"的变量, 我们称他为 "全局" 环境.</p>
<p>如有可能，你应该设法避免使用 <span class="pykeyword">全局变量</span>, 因为他们可能导致你不期望的对变量的修改.  在编程中, <span class="pykeyword">全局</span>通常是不好的.</p>

<!--==============================-->
<hr width="50%">
<h3 class="section">越界</h3>
<p>Larry 和 Curly 一起兴冲冲的走着.  突然, Moe 朝着他的朋友们从远处跑来.   正当 Moe 马上就要遇上 Larry 和 Curly的时候, 他越界了并从屏幕消失. 如果你想要他遇上他的朋友们, 你需要删除那三个 <span class="comment">#</span> .</p>

<pre>
Larry = UsedRobot(colour=<span class="string">'blue'</span>)
Curly = UsedRobot(1, 3, colour=<span class="string">'green'</span>)

<span class="comment"># Using two keywords you haven't seen yet!</span>
<span class="keyword">for</span> i <span class="keyword">in</span> range(3):
    Larry.move()
    Curly.move()

<span class="keyword">def</span> wait_for_me():
    <span class="comment">#global Moe</span>
    Moe = UsedRobot(1, 2, colour=<span class="string">'yellow'</span>)
    <span class="comment"># Using two same new keywords again!</span>
    <span class="keyword">for</span> i <span class="keyword">in</span> range(3):
        Moe.move()
        Larry.move()
        Moe.move()
        Curly.move()

wait_for_me()
<span class="comment"># first image below; Moe is there.</span>
Larry.move()
<span class="comment"># second image below; Moe is gone.</span>
Curly.move()
<span class="comment">#Moe.move()</span>
Larry.move()
Curly.move()
<span class="comment">#Moe.move()</span>
Larry.turn_off()
</pre>

<p><img alt="Moe there"  src="../../images/future/scope1.png"></p>
<p><img alt="Moe gone"  src="../../images/future/scope2.png"></p>
<!--==============================-->
<hr width="50%">
<h3 class="try">试试看!</h3>
<p>在乐跑机器人的世界,亲自尝试一下这个程序, 做一些改变,使得Moe遇上他的朋友!</p>

<center><a href="30-dot.htm"><img alt="previous" src=
"../../images/previous.png">面向对象的编程:  "点" 记数法.</a> - <a href=
"../lessons_toc.htm"><img alt="home" src="../../images/home.png"></a> - <a href=
"32-return.htm">很多返回<img alt="next"
src="../../images/next.png"></a></center>

</body>
</html>
